﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace UICommon
{
	/// <summary>
	/// DataGridViewDateTextBoxCellオブジェクトの列を表します。
	/// </summary>
	public class DataGridViewNumTextBoxColumn : DataGridViewColumn
	{
		/// <summary>
		/// CellTemplateとするDataGridViewDateTextBoxCellオブジェクトを指定して 基本クラスのコンストラクタを呼び出す
		/// </summary>
		public DataGridViewNumTextBoxColumn()
		: base( new DataGridViewNumTextBoxCell() )
		{}

		/// <summary>
		/// CellTemplateの取得と設定
		/// </summary>
		public override DataGridViewCell CellTemplate
		{
			get
			{
				return base.CellTemplate;
			}
			set
			{
				//DataGridViewDateTextBoxCellしかCellTemplateに設定できないようにする
				if( !( value is DataGridViewNumTextBoxCell ) )
				{
					throw new InvalidCastException( "DataGridViewDateTextBoxCellオブジェクトを指定してください" );
				}
				base.CellTemplate = value;
			}
		}
	}

	/// <summary>
	/// MaskedTextBoxで編集できるテキスト情報をDataGridViewコントロールに表示します。
	/// </summary>
	public class DataGridViewNumTextBoxCell : DataGridViewTextBoxCell
	{
		/// <summary>
		/// コンストラクタ
		/// </summary>
		public DataGridViewNumTextBoxCell()
		{}

		/// <summary>
		/// 編集コントロールを初期化する
		/// 編集コントロールは別のセルや列でも使いまわされるため、初期化の必要がある
		/// </summary>
		/// <param name="rowIndex"></param>
		/// <param name="initialFormattedValue"></param>
		/// <param name="dataGridViewCellStyle"></param>
		public override void InitializeEditingControl( int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle )
		{
			base.InitializeEditingControl( rowIndex, initialFormattedValue, dataGridViewCellStyle );

			//編集コントロールの取得
			DataGridViewNumTextBoxEditingControl NumBox = this.DataGridView.EditingControl as DataGridViewNumTextBoxEditingControl;
			if( NumBox != null )
			{
				//Textを設定
				if( this.RowIndex < 0 || this.ColumnIndex < 0 )
				{
					return;
				}

				NumBox.Text = this.Value != null ? this.Value.ToString() : "1";
			}
		}

		/// <summary>
		/// 編集コントロールの型を指定する
		/// </summary>
		public override Type EditType
		{
			get
			{
				return typeof( DataGridViewNumTextBoxEditingControl );
			}
		}

		/// <summary>
		/// セルの値のデータ型を指定する。ここでは、Object型とする。基本クラスと同じなので、オーバーライドの必要なし
		/// </summary>
		public override Type ValueType
		{
			get
			{
				return typeof( object );
			}
		}

		/// <summary>
		/// 新しいレコード行のセルの既定値を指定する
		/// </summary>
		public override object DefaultNewRowValue
		{
			get
			{
				return base.DefaultNewRowValue;
			}
		}
	}

	/// <summary>
	/// DataGridViewDateTextBoxCellでホストされるMaskedTextBoxコントロールを表します。
	/// </summary>
	public class DataGridViewNumTextBoxEditingControl : NumericUpDown, IDataGridViewEditingControl
	{
		//編集コントロールが表示されているDataGridView
		DataGridView dataGridView;

		//編集コントロールが表示されている行
		int rowIndex;

		//編集コントロールの値とセルの値が違うかどうか
		bool valueChanged;

		/// <summary>
		/// コンストラクタ
		/// </summary>
		public DataGridViewNumTextBoxEditingControl()
		{
			this.TabStop = false;
			this.Minimum = 0.0M;
			this.Maximum = 16.0M;
			this.Increment = 0.5M;
			this.DecimalPlaces = 1;
		}

		#region IDataGridViewEditingControl メンバ
		/// <summary>
		/// 編集コントロールで変更されたセルの値
		/// </summary>
		/// <param name="context"></param>
		/// <returns></returns>
		public object GetEditingControlFormattedValue( DataGridViewDataErrorContexts context )
		{
			return this.Text;
		}

		/// <summary>
		/// 編集コントロールで変更されたセルの値
		/// </summary>
		public object EditingControlFormattedValue
		{
			get
			{
				return this.GetEditingControlFormattedValue( DataGridViewDataErrorContexts.Formatting );
			}
			set
			{
				this.Text = ( string )value;
			}
		}

		/// <summary>
		/// セルスタイルを編集コントロールに適用する
		/// 編集コントロールの前景色、背景色、フォントなどをセルスタイルに合わせる
		/// </summary>
		/// <param name="dataGridViewCellStyle"></param>
		public void ApplyCellStyleToEditingControl( DataGridViewCellStyle dataGridViewCellStyle )
		{
			this.Font = dataGridViewCellStyle.Font;
			this.ForeColor = dataGridViewCellStyle.ForeColor;
			this.BackColor = dataGridViewCellStyle.BackColor;
			switch( dataGridViewCellStyle.Alignment )
			{
			case DataGridViewContentAlignment.BottomCenter:
			case DataGridViewContentAlignment.MiddleCenter:
			case DataGridViewContentAlignment.TopCenter:
				this.TextAlign = HorizontalAlignment.Center;
				break;

			case DataGridViewContentAlignment.BottomRight:
			case DataGridViewContentAlignment.MiddleRight:
			case DataGridViewContentAlignment.TopRight:
				this.TextAlign = HorizontalAlignment.Right;
				break;

			default:
				this.TextAlign = HorizontalAlignment.Left;
				break;
			}
		}

		/// <summary>
		/// 編集するセルがあるDataGridView
		/// </summary>
		public DataGridView EditingControlDataGridView
		{
			get
			{
				return this.dataGridView;
			}
			set
			{
				this.dataGridView = value;
			}
		}

		/// <summary>
		/// 編集している行のインデックス
		/// </summary>
		public int EditingControlRowIndex
		{
			get
			{
				return this.rowIndex;
			}
			set
			{
				this.rowIndex = value;
			}
		}

		/// <summary>
		/// 値が変更されたかどうか
		/// 編集コントロールの値とセルの値が違うかどうか
		/// </summary>
		public bool EditingControlValueChanged
		{
			get
			{
				return this.valueChanged;
			}
			set
			{
				this.valueChanged = value;
			}
		}

		/// <summary>
		/// 指定されたキーをDataGridViewが処理するか、編集コントロールが処理するかTrueを返すと、編集コントロールが処理する
		/// dataGridViewWantsInputKeyがTrueの時は、DataGridViewが処理できる
		/// </summary>
		/// <param name="keyData"></param>
		/// <param name="dataGridViewWantsInputKey"></param>
		/// <returns></returns>
		public bool EditingControlWantsInputKey( Keys keyData, bool dataGridViewWantsInputKey )
		{
			//Keys.Left、Right、Home、Endの時は、Trueを返す
			//このようにしないと、これらのキーで別のセルにフォーカスが移ってしまう
			switch( keyData & Keys.KeyCode )
			{
			case Keys.Right:
			case Keys.End:
			case Keys.Left:
			case Keys.Home:
				return true;
			default:
				return false;
			}
		}

		/// <summary>
		/// マウスカーソルがEditingPanel上にあるときのカーソルを指定する
		/// EditingPanelは編集コントロールをホストするパネルで、
		/// 編集コントロールがセルより小さいとコントロール以外の部分がパネルとなる
		/// </summary>
		public Cursor EditingPanelCursor
		{
			get
			{
				return base.Cursor;
			}
		}

		/// <summary>
		/// コントロールで編集する準備をする。テキストを選択状態にしたり、挿入ポインタを末尾にしたりする
		/// </summary>
		/// <param name="selectAll"></param>
		public void PrepareEditingControlForEdit( bool selectAll )
		{
			//if (selectAll)
			//{
			//    //選択状態にする
			//    this.BeginInit();
			//}
			//else
			//{
			//    //挿入ポインタを末尾にする
			//    //this.EndInvoke(); 
			//}
		}

		/// <summary>
		/// 値が変更した時に、セルの位置を変更するかどうかが変更された時に編集コントロールの大きさが変更される時はTrue
		/// </summary>
		public bool RepositionEditingControlOnValueChange
		{
			get
			{
				return false;
			}
		}

		#endregion

		/// <summary>
		/// 値が変更された時
		/// </summary>
		/// <param name="e"></param>
		protected override void OnValidated( EventArgs e )
		{
			base.OnValidated( e );
			this.dataGridView.NotifyCurrentCellDirty( true );
		}
	}
}